home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2 Examples.sit / Raven 1.2 Examples / Quill / Source / PaneEditDialog.cpp < prev    next >
Text File  |  1997-08-26  |  14KB  |  590 lines

  1. /*
  2.  *    File:        PaneEditDialog.cpp
  3.  *    Function:    A dialog box that knows how to edit panes.
  4.  *    Written by:    Jesse Jones
  5.  *
  6.  *  Copyright ゥ 1996-1997 Jesse Jones. 
  7.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  8.  *
  9.  *    Change History (most recent first):
  10.  *
  11.  *         <2>     5/11/97    JDJ        Uses GetNamedResource instead of Get1NamedResource.
  12.  *         <1>    11/20/96    JDJ        Created (from CPaneDialog)
  13.  */
  14.  
  15. #include "PaneEditDialog.h"
  16.  
  17. #include <Resources.h>
  18.  
  19. #include <ZApplication.h>
  20. #include <ZAttributes.h>
  21. #include <ZDialogHandler.h>
  22. #include <ZHierarchicalTableExtras.h>
  23. #include <ZIntConversions.h>
  24. #include <ZMiscUtils.h>
  25. #include "ZPaneNode.h"
  26. #include <ZScroller.h>
  27. #include <ZSubNode.h>
  28. #include <ZStringUtils.h>
  29. #include <ZUndoableCommand.h>
  30. #include <ZUndoMgr.h>
  31.  
  32. #include "BasePaneEditor.h"
  33. #include "DialogBoxProxy.h"
  34. #include "ViewContainer.h"
  35. #include "WindowProxy.h"
  36.  
  37.  
  38. //-----------------------------------
  39. //    Constants
  40. //
  41. const string kApplyMessage = "Apply";
  42.  
  43.  
  44. //-----------------------------------
  45. //    Types
  46. //
  47. typedef THierarchicalIter<TPaneNode> CNodeIter;
  48.  
  49.  
  50. // ===================================================================================
  51. //    class CUpdateResourceCommand
  52. // ===================================================================================
  53. class CUpdateResourceCommand : public TUndoableCommand {
  54.  
  55.     typedef TUndoableCommand Inherited;
  56.  
  57. //-----------------------------------
  58. //    Initialization/Destruction
  59. //
  60. public:
  61.     virtual             ~CUpdateResourceCommand();
  62.     
  63.                         CUpdateResourceCommand(TPane* pane);
  64.     
  65. //-----------------------------------
  66. //    New API
  67. //
  68. public:
  69.             CViewContainer*    GetContainer();
  70.  
  71. //-----------------------------------
  72. //    Inherited API
  73. //
  74. public:
  75.     virtual string        GetText() const;
  76.  
  77. protected:
  78.     virtual void         OnDo();
  79.  
  80.     virtual void         OnUndo();
  81.  
  82.     virtual void         OnRedo();
  83.             
  84. //-----------------------------------
  85. //    Member data
  86. //
  87. protected:
  88.     TPane*    mPane;
  89. };
  90.  
  91.  
  92. //---------------------------------------------------------------
  93. //
  94. // CUpdateResourceCommand::~CUpdateResourceCommand
  95. //
  96. //---------------------------------------------------------------
  97. CUpdateResourceCommand::~CUpdateResourceCommand()
  98. {
  99. }
  100.  
  101.  
  102. //---------------------------------------------------------------
  103. //
  104. // CUpdateResourceCommand::CUpdateResourceCommand
  105. //
  106. //---------------------------------------------------------------
  107. CUpdateResourceCommand::CUpdateResourceCommand(TPane* pane)
  108. {
  109.     ASSERT(pane != nil);
  110.     
  111.     mPane = pane;
  112.  
  113.     TWindow* window = dynamic_cast<TWindow*>(mPane->GetTopView());
  114.     if (window != nil)
  115.         mContext = window->GetUndoContext();
  116.     else
  117.         mContext = nil;
  118.     mDelete  = mContext == nil;
  119. }
  120.  
  121.  
  122. //---------------------------------------------------------------
  123. //
  124. // CUpdateResourceCommand::GetContainer
  125. //
  126. //---------------------------------------------------------------
  127. CViewContainer*    CUpdateResourceCommand::GetContainer()
  128. {
  129.     CViewContainer* container = nil;
  130.     
  131.     TView* superView = mPane->GetSuperView();
  132.     if (superView == nil) {
  133.         if (TView* view = dynamic_cast<TView*>(mPane))
  134.             container = dynamic_cast<CViewContainer*>(view->FindSubPane("CViewContainer"));
  135.     
  136.     } else {
  137.         container = dynamic_cast<CViewContainer*>(superView);
  138.         while (container == nil && superView != nil) {
  139.             superView = superView->GetSuperView();
  140.             container = dynamic_cast<CViewContainer*>(superView);
  141.         }
  142.     }
  143.         
  144.     ASSERT(container != nil);
  145.     
  146.     return container;
  147. }
  148.  
  149.  
  150. //---------------------------------------------------------------
  151. //
  152. // CUpdateResourceCommand::GetText
  153. //
  154. //---------------------------------------------------------------
  155. string CUpdateResourceCommand::GetText() const
  156. {
  157.     return "";                                // should be inside a transaction
  158. }
  159.  
  160.  
  161. //---------------------------------------------------------------
  162. //
  163. // CUpdateResourceCommand::OnDo
  164. //
  165. //---------------------------------------------------------------
  166. void CUpdateResourceCommand::OnDo()
  167. {
  168.     this->GetContainer()->UpdateResource();
  169. }
  170.  
  171.  
  172. //---------------------------------------------------------------
  173. //
  174. // CUpdateResourceCommand::OnUndo
  175. //
  176. //---------------------------------------------------------------
  177. void CUpdateResourceCommand::OnUndo()
  178. {
  179.     this->GetContainer()->UpdateResource();
  180. }
  181.  
  182.  
  183. //---------------------------------------------------------------
  184. //
  185. // CUpdateResourceCommand::OnRedo
  186. //
  187. //---------------------------------------------------------------
  188. void CUpdateResourceCommand::OnRedo()
  189. {
  190.     this->GetContainer()->UpdateResource();
  191. }
  192.  
  193. #pragma mark -
  194.  
  195. // ===================================================================================
  196. //    class CPaneEditDialog
  197. // ===================================================================================
  198.  
  199. static TReanimatorRegister<CPaneEditDialog> sPaneEditDialogRegistrar;
  200.  
  201. //---------------------------------------------------------------
  202. //
  203. // CPaneEditDialog::~CPaneEditDialog
  204. //
  205. //---------------------------------------------------------------
  206. CPaneEditDialog::~CPaneEditDialog()
  207. {
  208. }
  209.  
  210.  
  211. //---------------------------------------------------------------
  212. //
  213. // CPaneEditDialog::CPaneEditDialog
  214. //
  215. //---------------------------------------------------------------
  216. CPaneEditDialog::CPaneEditDialog()
  217. {
  218.     mPane  = nil;
  219.     mTable = nil;
  220.     
  221.     mAttributes.eraseOnUpdate = false;
  222. }
  223.  
  224.  
  225. //---------------------------------------------------------------
  226. //
  227. // CPaneEditDialog::EditPane                            [static]
  228. //
  229. //---------------------------------------------------------------
  230. void CPaneEditDialog::EditPane(TPane* pane)
  231. {
  232.     CPaneEditDialog* dialog = CPaneEditDialog::Create(240, TApplication::Instance());
  233.     dialog->SetPane(pane);
  234.     
  235.     string message = kNothingMessage;
  236.     
  237.     {
  238.     TDialogHandler handler(dialog);
  239.         dialog->Show();
  240.     
  241.         while (message != kCancelMessage && message != kOKMessage) {
  242.             message = handler.ProcessNextEvent();
  243.  
  244.             if (message == kOKMessage) {
  245.                 if (dialog->Validate())
  246.                     dialog->Commit();
  247.                 else
  248.                     message = kNothingMessage;
  249.             
  250.             } else if (message == kApplyMessage) {
  251.                 if (dialog->Validate())
  252.                     dialog->Apply();
  253.                 else
  254.                     message = kNothingMessage;
  255.             
  256.             } else if (message == kCancelMessage)
  257.                 dialog->Revert();
  258.         }
  259.     }
  260. }
  261.  
  262.  
  263. //---------------------------------------------------------------
  264. //
  265. // CPaneEditDialog::SetPane
  266. //
  267. //---------------------------------------------------------------
  268. void CPaneEditDialog::SetPane(TPane* inPane)
  269. {
  270.     ASSERT(inPane != nil);
  271.     
  272.     if (dynamic_cast<CViewContainer*>(inPane) != nil)
  273.         inPane = inPane->GetSuperView();
  274.  
  275.     mPane = inPane;
  276.     
  277.     // Move the dialog to where the user last had it.
  278.     if (mPane->HasAttribute("Editor Frame")) {
  279.         TRectAttribute* attribute = dynamic_cast<TRectAttribute*>(mPane->GetAttribute("Editor Frame"));
  280.         this->SetLocation(attribute->GetValue()[topLeft]);
  281.         this->ForceOnScreen();
  282.     }
  283.     
  284.     // Install the applicable editors.
  285.     this->CreateEditors();
  286.     
  287.     // Tell the pane editors the pane they're working on.
  288.     CNodeIter iter(mTable);
  289.     while (iter) {
  290.         TPaneNode* node = *iter;
  291.         ++iter;
  292.  
  293.         TPane* pane = node->GetPane();
  294.         
  295.         if (CRootPaneEditor* editor = dynamic_cast<CRootPaneEditor*>(pane))
  296.             editor->SetPane(mPane);
  297.     }    
  298. }
  299.  
  300.  
  301. //---------------------------------------------------------------
  302. //
  303. // CPaneEditDialog::Validate
  304. //
  305. //---------------------------------------------------------------
  306. bool CPaneEditDialog::Validate() const
  307. {
  308.     bool valid = Inherited::Validate();
  309.     
  310.     CNodeIter iter(mTable);
  311.     while (iter && valid) {
  312.         TPaneNode* node = *iter;
  313.         ++iter;
  314.  
  315.         TPane* pane = node->GetPane();
  316.         
  317.         if (CRootPaneEditor* editor = dynamic_cast<CRootPaneEditor*>(pane))
  318.             valid = editor->Validate();
  319.     }
  320.     
  321.     return valid;
  322. }
  323.     
  324.     
  325. //---------------------------------------------------------------
  326. //
  327. // CPaneEditDialog::Apply
  328. //
  329. //---------------------------------------------------------------
  330. void CPaneEditDialog::Apply()
  331. {
  332.     try {
  333.         CNodeIter iter(mTable);
  334.         while (iter) {
  335.             TPaneNode* node = *iter;
  336.             ++iter;
  337.  
  338.             TPane* pane = node->GetPane();
  339.                     
  340.             if (CRootPaneEditor* editor = dynamic_cast<CRootPaneEditor*>(pane))
  341.                 editor->Apply();
  342.         }
  343.  
  344.     } catch (const TBaseException& e) {
  345.         ReportError(LoadAppString("Couldn't apply the pane changes"), e);
  346.     
  347.     } catch (...) {
  348.         ReportError(LoadAppString("Couldn't apply the pane changes"), LoadAppString("Unknown Error"));
  349.     }
  350. }
  351.     
  352.     
  353. //---------------------------------------------------------------
  354. //
  355. // CPaneEditDialog::Commit
  356. //
  357. //---------------------------------------------------------------
  358. void CPaneEditDialog::Commit()
  359. {
  360.     TWindow* window = dynamic_cast<TWindow*>(mPane->GetTopView());
  361.     if (window != nil) {
  362.         string text = LoadIndString(257, 2);        
  363.         TMultipleUndoableCommand* command = new TMultipleUndoableCommand(window->GetUndoContext(), text);
  364.         
  365.         try {
  366.             CNodeIter iter(mTable);
  367.             while (iter) {
  368.                 TPaneNode* node = *iter;
  369.                 ++iter;
  370.  
  371.                 TPane* pane = node->GetPane();
  372.                                 
  373.                 if (CRootPaneEditor* editor = dynamic_cast<CRootPaneEditor*>(pane))
  374.                     editor->Commit(command);
  375.             }
  376.             
  377.             command->AddCommand(new CUpdateResourceCommand(mPane));
  378.             command->Post();
  379.     
  380.         } catch (const TBaseException& e) {
  381.             delete command;
  382.             ReportError(LoadAppString("Couldn't change the pane"), e);
  383.         
  384.         } catch (...) {
  385.             delete command;
  386.             ReportError(LoadAppString("Couldn't change the pane"), LoadAppString("Unknown Error"));
  387.         }
  388.     }
  389. }
  390.  
  391.  
  392. //---------------------------------------------------------------
  393. //
  394. // CPaneEditDialog::Revert
  395. //
  396. //---------------------------------------------------------------
  397. void CPaneEditDialog::Revert()
  398. {
  399.     try {
  400.         CNodeIter iter(mTable);
  401.         while (iter) {
  402.             TPaneNode* node = *iter;
  403.             ++iter;
  404.  
  405.             TPane* pane = node->GetPane();
  406.                                     
  407.             if (CRootPaneEditor* editor = dynamic_cast<CRootPaneEditor*>(pane))
  408.                 editor->Revert();
  409.         }
  410.     
  411.     } catch (const TBaseException& e) {
  412.         ReportError(LoadAppString("Couldn't revert the pane changes"), e);
  413.     
  414.     } catch (...) {
  415.         ReportError(LoadAppString("Couldn't revert the pane changes"), LoadAppString("Unknown Error"));
  416.     }
  417. }
  418.  
  419.  
  420. //---------------------------------------------------------------
  421. //
  422. // CPaneEditDialog::Create                                [static]
  423. //
  424. //---------------------------------------------------------------
  425. CPaneEditDialog* CPaneEditDialog::Create(ResID id, MCommander* superCommander)
  426. {
  427.     CPaneEditDialog* dialog = dynamic_cast<CPaneEditDialog*>(Inherited::Create(id, superCommander));
  428.     
  429.     try {
  430.         if (dialog == nil)
  431.             throw TRuntimeException("CPaneEditDialog::Create created an object that wasn't the right type.");
  432.  
  433.     } catch (...) {
  434.         delete dialog;
  435.         throw;
  436.     }
  437.     
  438.     return dialog;
  439. }
  440.  
  441.                             
  442. //---------------------------------------------------------------
  443. //
  444. // CPaneEditDialog::Create                                [static]
  445. //
  446. //---------------------------------------------------------------
  447. MReanimatable* CPaneEditDialog::Create(MReanimatable* parent)
  448. {
  449.     ASSERT(parent == nil);
  450.     
  451.     if (CWindowProxy::msUseProxy)
  452.         return CDialogBoxProxy::Create(parent);
  453.     else
  454.         return new CPaneEditDialog;
  455. }
  456.  
  457.  
  458. //---------------------------------------------------------------
  459. //
  460. // CPaneEditDialog::OnReanimated
  461. //
  462. //---------------------------------------------------------------
  463. void CPaneEditDialog::OnReanimated()
  464. {
  465.     Inherited::OnReanimated();
  466.     
  467.     TPushButton* control = dynamic_cast<TPushButton*>(this->FindSubPane("Apply"));
  468.     if (control != nil)
  469.         control->AddListener(this);
  470.  
  471.     mTable = dynamic_cast<THierarchicalTable*>(this->FindSubPane("Table View"));
  472.     
  473.     TScroller* scroller = dynamic_cast<TScroller*>(this->FindSubPane("Scroller"));    // ・・ハshould do this from within Quill
  474.     if (scroller == nil)
  475.         throw TRuntimeException("we're hosed");
  476.     scroller->InstallView(mTable);
  477. }
  478.  
  479.  
  480. //---------------------------------------------------------------
  481. //
  482. // CPaneEditDialog::OnClose
  483. //
  484. //---------------------------------------------------------------
  485. void CPaneEditDialog::OnClose()
  486. {
  487.     if (mPane != nil) {
  488.         if (!mPane->HasAttribute("Editor Frame"))
  489.             mPane->AddAttribute("Editor Frame", new TRectAttribute);
  490.             
  491.         TRectAttribute* attribute = dynamic_cast<TRectAttribute*>(mPane->GetAttribute("Editor Frame"));
  492.         attribute->SetValue(this->GetFrame());
  493.     }
  494.     
  495.     Inherited::OnClose();
  496. }
  497.  
  498.  
  499. //---------------------------------------------------------------
  500. //
  501. // CPaneEditDialog::GetTable    
  502. //
  503. //---------------------------------------------------------------
  504. Handle CPaneEditDialog::GetTable()
  505. {
  506.     Handle table = nil;
  507.     
  508.     string className = typeid(*mPane).name();
  509.     table = GetNamedResource('EdId', StrToPStr(className));
  510.     
  511.     if (table == nil)                                    // should only happen when editing Quill's views
  512.         table = GetNamedResource('EdId', "¥pTPane");
  513.  
  514.     ThrowIfResFail(table);
  515.     
  516.     return table;
  517. }
  518.  
  519.  
  520. //---------------------------------------------------------------
  521. //
  522. // CPaneEditDialog::CreateEditors
  523. //
  524. //---------------------------------------------------------------
  525. void CPaneEditDialog::CreateEditors()
  526. {
  527.     #pragma options align=mac68k
  528.     struct SEditorTable {
  529.         short             count;
  530.         unsigned char    editStr[1];
  531.     };
  532.     #pragma options align=reset
  533.  
  534.     SEditorTable** tableH = (SEditorTable**) this->GetTable();
  535.     
  536.     HLock((Handle) tableH);
  537.             
  538.     unsigned char* editStr = (**tableH).editStr;
  539.     
  540.     for (short index = 0; index < (**tableH).count; index++) {
  541.         string str = PStrToStr(editStr);
  542.         
  543.         string name = Parse(str, " ¥t");
  544.  
  545.         TSubNode* parent = new TSubNode(mTable, mTable->GetRoot(), name, true);
  546.         mTable->GetRoot()->AppendNode(parent);
  547.         
  548.         if (str[0] == '[') {
  549.             str = str.substr(1);
  550.  
  551.             while (str.length() > 0) {
  552.                 bool expand = true;
  553.                 if (str[0] == '>') {
  554.                     expand = false;
  555.                     str = str.substr(1);
  556.                 }
  557.                 
  558.                 ResID id = StrToShort(Parse(str, " ¥t"));
  559.  
  560.                 // Panes that use the Control Manager need to be initialized with
  561.                 // a valid port so we'll create the pane in the context it will
  562.                 // be drawn in and then detach it (so we don't get hosed by
  563.                 // origin adjustments when drawing the pane).
  564.                 TPane* editor = TPane::Create(id, this);
  565.                 this->RemoveSubPane(editor);
  566.                 
  567.                 TSubNode* subNode = new TSubNode(mTable, parent, editor->GetName(), expand);
  568.                 parent->AppendNode(subNode);
  569.  
  570.                 TPaneNode* leafNode = new TPaneNode(mTable, subNode, editor);
  571.                 subNode->AppendNode(leafNode);
  572.             }
  573.                     
  574.         } else {
  575.             ResID id = StrToShort(Parse(str, " ¥t"));
  576.             TPane* editor = TPane::Create(id, this);
  577.             this->RemoveSubPane(editor);
  578.             
  579.             TPaneNode* leafNode = new TPaneNode(mTable, parent, editor);
  580.             parent->AppendNode(leafNode);
  581.         }
  582.         
  583.         editStr += *editStr + 1;
  584.     }
  585.     
  586.     ReleaseResource((Handle) tableH);
  587. }
  588.  
  589.  
  590.